#include <stdlib.h>
#include "Arbre.h"
#include "Symbole.h"
#include "SymboleValue.h"

////////////////////////////////////////////////////////////////////////////////
// NoeudSeqInst
////////////////////////////////////////////////////////////////////////////////
NoeudSeqInst::NoeudSeqInst() : tabInst() {}

    ////////////////////////////////////////////////////////////////////////////////
    int NoeudSeqInst::getValeur() {
      for (unsigned int i=0; i<tabInst.size(); i++)
        tabInst[i]->getValeur();  // on evalue chaque instruction de la séquence
      return 1; // par convention, resultat = 1
    }

    ////////////////////////////////////////////////////////////////////////////////
    void NoeudSeqInst::afficher(unsigned short ind) {
      Noeud::afficher(ind);
      cout << "Noeud - Sequence de " << tabInst.size() << " instruction(s)" << endl;
      for (unsigned int i=0; i<tabInst.size(); i++)
      tabInst[i]->afficher(ind+1); // on affiche les fils en augmentant l'i
    }

    ////////////////////////////////////////////////////////////////////////////////
    void NoeudSeqInst::ajouteInstruction(Noeud* instruction) {
      tabInst.push_back(instruction);
    }

////////////////////////////////////////////////////////////////////////////////
// NoeudAffectation
////////////////////////////////////////////////////////////////////////////////
NoeudAffectation::NoeudAffectation(Noeud* variable, Noeud* expression) {
      this->variable=variable;  this->expression=expression; }

    ////////////////////////////////////////////////////////////////////////////////
    int NoeudAffectation::getValeur() {
      int valeur = expression->getValeur(); // on évalue l'expression
      ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
      return valeur; // par convention, une affectation a pour valeur la valeur affectée
    }

    ////////////////////////////////////////////////////////////////////////////////
    void NoeudAffectation::afficher(unsigned short ind) {
      Noeud::afficher(ind);
      cout << "Noeud - Affectation" << endl;
      variable->afficher(ind+1);   // on affiche variable et expression
      expression->afficher(ind+1); // en augmentant l'indentation
    }

////////////////////////////////////////////////////////////////////////////////
// NoeudOperateurBinaire
////////////////////////////////////////////////////////////////////////////////
NoeudOperateurBinaire::NoeudOperateurBinaire ( Symbole operateur, Noeud* operandeGauche,  Noeud* operandeDroit) {
      this->operateur=operateur; this->operandeGauche=operandeGauche; this->operandeDroit=operandeDroit; }

    ////////////////////////////////////////////////////////////////////////////////
    int NoeudOperateurBinaire::getValeur() { 
      int valeur=0;
      int og=operandeGauche->getValeur();
      int od=operandeDroit->getValeur();
      if      (this->operateur=="+") valeur = og+od;
      else if (this->operateur=="-") valeur = og-od;
      else if (this->operateur=="*") valeur = og*od;
      else if (this->operateur=="et") valeur = og&&od;
      else if (this->operateur=="ou") valeur = og||od;
      else if (this->operateur=="non") valeur = !od;
      else if (this->operateur=="==") valeur = og==od;
      else if (this->operateur=="!=") valeur = og!=od;
      else if (this->operateur=="<") valeur = og<od;
      else if (this->operateur=="<=") valeur = og<=od;
      else if (this->operateur==">") valeur = og>od;
      else if (this->operateur==">=") valeur = og>=od;
//reste a gerer le - booleen => try og value ?
      else  // this->operateur=="/" //retourne valeur
            if (od!=0)
                    valeur = og/od;
            else {
                    cout << "Erreur pendant l'interpretation : division par zero" << endl;
                    exit(0); // plus tard on levera une exception
            }
      return valeur;
    }

    ////////////////////////////////////////////////////////////////////////////////
    void NoeudOperateurBinaire::afficher(unsigned short ind) {
      Noeud::afficher(ind);
      cout << "Noeud - Operateur Binaire \"" << this->operateur.getChaine() << "\" applique a : " << endl;
      operandeGauche->afficher(ind+1);  // on affiche fils gauche et fils droit
      operandeDroit->afficher(ind+1);   // en augmentant l'i
    }

////////////////////////////////////////////////////////////////////////////////
// NoeudTerms
////////////////////////////////////////////////////////////////////////////////
    void NoeudTerms::afficher(unsigned short ind) {
        Noeud::afficher(ind);
        cout << "Noeud - " << this->instruction << endl; 
        expBool->afficher(ind+1); 
        seqInst->afficher(ind+1); 
    }
    
    int NoeudTerms::getValeur() {
        int valeur =0;

        if (this->instruction=="Si" || this->instruction=="Sinonsi" || this->instruction=="Sinon" || this->instruction=="Cas"  || this->instruction=="Defaut" || this->instruction=="Pour")
        {
                if(expBool->getValeur()) { valeur = seqInst->getValeur(); } 
        }
        else if (this->instruction=="Repeter")
        { 
                valeur = seqInst->getValeur();  
                while(!expBool->getValeur()) { valeur = seqInst->getValeur(); } 
        }
        else //tant que
        {
                while(expBool->getValeur()) { valeur = seqInst->getValeur(); }
         }
        
        return valeur;  //on retourne la derniere valeur
    }

////////////////////////////////////////////////////////////////////////////////
// NoeudInstSi
////////////////////////////////////////////////////////////////////////////////
    void NoeudInstSi::addCondition(string name, Noeud* expBool, Noeud* seqInst) { //ajouter un si/sinonsi/sinon
        NoeudTerms* si = new NoeudTerms(name, expBool, seqInst);
        ens.push_back(si);
    }
    
    void NoeudInstSi::afficher(unsigned short ind) {
        vector<NoeudTerms *>::iterator it; 
        for (it=ens.begin(); it!=ens.end(); it++) { (*it)->afficher(ind); }
    }
    
    int NoeudInstSi::getValeur() {
        int valeur = 0;
        vector<NoeudTerms *>::iterator it; 
        for (it=ens.begin(); it!=ens.end(); it++)
        {
            valeur = (*it)->getValeur();
            if(valeur!=0) return valeur;
        }
        return valeur;
    }

////////////////////////////////////////////////////////////////////////////////
// NoeudInstTq //fait dans NoeudTerms
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// NoeudInstRepeter //fait dans NoeudTerms
////////////////////////////////////////////////////////////////////////////////
    
////////////////////////////////////////////////////////////////////////////////
// NoeudInstPour
////////////////////////////////////////////////////////////////////////////////
    void NoeudInstPour::afficher(unsigned short ind) {
        Noeud::afficher(ind); cout << "Noeud - Pour" << endl; 
        
        a1->afficher(ind+1);
        expBool->afficher(ind+1); 
        a2->afficher(ind+1);
        seqInst->afficher(ind+1);
    }
    
    int NoeudInstPour::getValeur() {
        int valeur =0;
        
        a1->getValeur();                                  //initialisation
        while(expBool->getValeur()) 
        { 
            valeur = seqInst->getValeur(); 
            a2->getValeur();                            //incrementation
        }
        
        return valeur;
    }

////////////////////////////////////////////////////////////////////////////////
// NoeudInstSelon
////////////////////////////////////////////////////////////////////////////////
   
    void NoeudInstSelon::addCase(string name, Noeud* cas, Noeud* seqInst) {
        NoeudTerms* si = new NoeudTerms(name, cas, seqInst);
        ens.push_back(si);
    }
    
    void NoeudInstSelon::afficher(unsigned short ind) {
        Noeud::afficher(ind);
        cout << "Noeud - Selon " << endl;

        vector<NoeudTerms *>::iterator it;
        for (it=ens.begin(); it!=ens.end(); it++)
        (*it)->afficher(ind+1);
    }
    
     int  NoeudInstSelon::getValeur() {
        int valeur = 0;
        vector<NoeudTerms *>::iterator it; 
        for (it=ens.begin(); it!=ens.end(); it++)
        {
            valeur = (*it)->getValeur();
            if(valeur!=0) return valeur;
        }
        return valeur;
     }
    
////////////////////////////////////////////////////////////////////////////////
// NoeudInstLire
////////////////////////////////////////////////////////////////////////////////
    void NoeudInstLire::afficher(unsigned short ind) {
        Noeud::afficher(ind);
        cout << "Noeud - Lire " << endl;
        var->afficher(ind + 1);
    }
    
    int NoeudInstLire::getValeur() {
        int k;
        cout << "<entrer une valeur>: "; cin >> k;
        ((SymboleValue*) var)->setValeur(k);
        return k;
    }

////////////////////////////////////////////////////////////////////////////////
// NoeudInstEcrire
////////////////////////////////////////////////////////////////////////////////
    void NoeudInstEcrire::afficher(unsigned short ind) {
        Noeud::afficher(ind);
        cout << "Noeud - Ecrire " << endl;
        it->afficher(ind + 1); 
    }
    
    int NoeudInstEcrire::getValeur() {
        cout <<  it->getValeur() << endl;
       return it->getValeur();
    }